package org.custom.spring.boot.security.filters;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.cleaver.spring.utils.servlet.ServletUtil;
import org.custom.spring.boot.entity.Result;
import org.custom.spring.boot.security.entity.SystemUser;
import org.custom.spring.boot.security.entity.security.SecurityProperties;
import org.custom.spring.boot.security.filters.abstracts.AbstractUnityCommonFilter;
import org.custom.spring.boot.security.service.SystemUserInfoService;
import org.custom.spring.boot.security.token.TokenManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import static cn.hutool.core.util.StrUtil.EMPTY;
import static org.custom.spring.boot.security.constant.SecurityConstant.AUTOMATIC_LOGIN;

/**
 * '自动登录' 认证拦截器
 *
 * @author LiKun
 * @date 2021/11/10 23:33
 */
@Component("rememberAuthenticationFilter")
public class RememberAuthenticationFilter extends AbstractUnityCommonFilter {
    public static final String PREFIX = AUTOMATIC_LOGIN + "*";

    @Resource
    private TokenManager redisTokenManager;
    @Resource
    private SystemUserInfoService systemUserInfoService;
    @Resource
    private SecurityProperties securityProperties;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    protected boolean requestFilterLogicalProcess(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        boolean requestAllowed2Proceed = true;
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        // 如果用户为进行认证且开启用户自动登录，则尝试对其 '自动登录'
        if (securityProperties.isOpenRemember() && (Objects.isNull(authentication) || !authentication.isAuthenticated())) {
            String tokenKey = this.getTokenKey(request.getRemoteAddr());

            if (StrUtil.isNotEmpty(tokenKey)) {
                Object token = redisTemplate.boundValueOps(tokenKey).get();

                if (ObjectUtil.isNotNull(token)) {
                    requestAllowed2Proceed = false;
                    String id = redisTokenManager.parseTokenId(String.valueOf(token));
                    SystemUser systemUser = systemUserInfoService.findSystemUserByUserId(id);
                    String recreateToken = redisTokenManager.generateAndTakeEffectToken(systemUser);

                    ServletUtil.write(Result.success(recreateToken), response);
                }
            }
        }

        return requestAllowed2Proceed;
    }

    /*-------------------------------------------------private methods------------------------------------------------*/

    /**
     * 获取匹配的 TokenKey 数据
     *
     * @param ip IP地址
     *
     * @return TokenKey
     */
    private String getTokenKey(String ip) {
        Set<String> keys = Optional.ofNullable(redisTemplate.keys(PREFIX)).orElse(Collections.emptySet());
        return keys.stream().filter(key -> key.endsWith(ip)).findFirst().orElse(EMPTY);
    }
}
